﻿using _3_NovaAdmin.Domain.ToolKits.Extensions;
using _5_NovaAdmin.Infrastructure.EntityConfigurations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace _5_NovaAdmin.Infrastructure.Persistence.Context;

/// <summary>
/// 定义数据库上下文对象
/// </summary>
public class AppDbContext : DbContext, _3_NovaAdmin.Domain.Abstractions.ITransaction
{

    /// <summary>
    /// 用于处理领域事件和命令
    /// </summary>
    protected IMediator _mediator;
    public readonly IServiceProvider serviceProvider;

    /// <summary>
    /// 构造函数，接收 DbContextOptions 参数
    /// </summary>
    /// <param name="options">用于传递数据库连接字符串、数据库提供程序等配置信息</param>
    /// <param name="mediator">用于处理领域事件和命令的 Mediator 组件</param>
    /// <param name="capBus">用于发布事件到消息队列或其他中间件的 ICapPublisher 组件</param>
    public AppDbContext(DbContextOptions options, IMediator mediator, IServiceProvider serviceProvider)
        : base(options) // 调用基类 DbContext 的构造函数，将配置信息传递给基类
    {
        _mediator = mediator;
        this.serviceProvider = serviceProvider;
    }

    public virtual DbSet<User> User { get; set; }
    public virtual DbSet<GroupMember> GroupMember { get; set; }
    public virtual DbSet<ChatGroup> ChatGroup { get; set; }
    public virtual DbSet<IdempotencyRecord> IdempotencyRecord { get; set; }

    /// <summary>
    /// 配置实体模型的映射关系和数据库表结构
    /// </summary>
    /// <param name="modelBuilder"></param>
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 添加实体配置  加载当前程序集中所有实现了IEntityTypeConfiguration接口的类
        modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
        //modelBuilder.AddSeed(); // 添加种子数据
        ConfigureAuditable(modelBuilder);
        ConfigureCompositeKey(modelBuilder);
        base.OnModelCreating(modelBuilder);
    }

    /// <summary>
    /// 添加审计功能的配置
    /// </summary>
    /// <param name="modelBuilder"></param>
    private void ConfigureAuditable(ModelBuilder modelBuilder)
    {
        // // 获取所有继承自 AuditableEntity<Guid> 的实体类型
        // var entityTypes = modelBuilder.Model.GetEntityTypes()
        //.Where(et => typeof(AuditableEntity<Guid>).IsAssignableFrom(et.ClrType)) // 筛选符合条件的实体
        //.ToList(); // 使用 ToList() 创建独立副本，以避免后续操作对原集合的修改  

        var entityTypes = modelBuilder.Model.GetEntityTypes()
                          .Where(et =>
                          {
                              var type = et.ClrType;
                              while (type != null) //递归调用（间接继承的情况）
                              {
                                  if (type.IsGenericType &&
                                      type.GetGenericTypeDefinition() == typeof(AuditableEntity<>))
                                      return true;
                                  type = type.BaseType;
                              }
                              return false;
                          })
                          .ToList();

        foreach (var entityType in entityTypes)
        {
            var entityClrType = entityType.ClrType; // 获取当前实体的 CLR 类型  

            // 获取 AuditableEntityBuilderExtensions 中的 ConfigureAuditable 方法  
            var method = typeof(AuditableEntityBuilderExtensions)
                .GetMethod("ConfigureAuditable", BindingFlags.Static | BindingFlags.Public);
            var genericMethod = method.MakeGenericMethod(entityClrType);

            // 动态调用泛型 Entity<T> 方法
            var entityMethod = typeof(ModelBuilder).GetMethod("Entity", Type.EmptyTypes);
            var genericEntityMethod = entityMethod.MakeGenericMethod(entityClrType);
            var entityBuilder = genericEntityMethod.Invoke(modelBuilder, null);

            // 调用扩展方法 ConfigureAuditable，并传入 entityBuilder  
            genericMethod.Invoke(null, new object[] { entityBuilder });
        }
    }

    /// <summary>
    /// 添加复合主键的配置
    /// 例如：builder.HasKey(p => new { p.UserId, p.GroupId });
    /// </summary>
    /// <param name="modelBuilder"></param>
    private void ConfigureCompositeKey(ModelBuilder modelBuilder)
    {
        // 扫描所有继承 CompositeEntity<> 的实体
        var compositeEntityGenericType = typeof(CompositeEntity<>).GetGenericTypeDefinition();

        var entityTypes = modelBuilder.Model.GetEntityTypes()
            .Where(et =>
                et.ClrType.BaseType != null &&
                et.ClrType.BaseType.IsGenericType &&
                et.ClrType.BaseType.GetGenericTypeDefinition() == compositeEntityGenericType
            )
            .ToList();

        foreach (var entityType in entityTypes)
        {
            var clrType = entityType.ClrType;
            var compositeKeyProps = clrType.GetProperties()
                .Where(p => p.IsDefined(typeof(CompositeKeyAttribute), false))
                .ToList();

            if (compositeKeyProps.Count > 0)
            {
                modelBuilder.Entity(clrType).HasKey(
                    compositeKeyProps.Select(p => p.Name).ToArray()
                );
            }
        }
    }

    #region 处理事务
    /// <summary>
    /// 定义一个私有字段 _currentTransaction，用于存储当前的数据库事务
    /// </summary>
    private IDbContextTransaction _currentTransaction;

    /// <summary>
    /// 获取当前正在进行的数据库事务
    /// </summary>
    /// <returns></returns>
    public IDbContextTransaction GetCurrentTransaction() => _currentTransaction;

    /// <summary>
    /// 如果有正在进行的事务，则返回 true；否则返回 false
    /// </summary>
    public bool HasActiveTransaction => _currentTransaction != null;

    /// <summary>
    /// 开始一个数据库事务
    /// </summary>
    /// <returns></returns>
    public Task<IDbContextTransaction> BeginTransactionAsync()
    {
        // 检查是否已经有一个正在进行的事务
        if (_currentTransaction != null) return null;
        // 开始一个新的事务，并将事务对象赋值给 _currentTransaction
        _currentTransaction = this.Database.BeginTransaction();
        return Task.FromResult(_currentTransaction);
    }

    /// <summary>
    /// 提交指定的数据库事务
    /// </summary>
    /// <param name="transaction">当前事务</param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="InvalidOperationException"></exception>
    public async Task CommitTransactionAsync(IDbContextTransaction transaction)
    {
        // 检查传入的 transaction 是否为 null
        if (transaction == null) throw new ArgumentNullException(nameof(transaction));

        // 检查传入的 transaction 是否是当前的事务
        if (transaction != _currentTransaction) throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current");

        try
        {
            // 调用 SaveChangesAsync 方法，将更改保存到数据库
            await SaveChangesAsync();

            // 提交事务
            transaction.Commit();
        }
        catch
        {
            // 如果发生异常，调用 RollbackTransaction 方法回滚事务
            RollbackTransaction();

            // 重新抛出异常
            throw;
        }
        finally
        {
            // 释放当前事务资源
            if (_currentTransaction != null)
            {
                _currentTransaction.Dispose();
                _currentTransaction = null;
            }
        }
    }

    // 回滚当前的数据库事务
    public void RollbackTransaction()
    {
        try
        {
            // 如果有正在进行的事务，调用 Rollback 方法回滚事务
            _currentTransaction?.Rollback();
        }
        finally
        {
            // 释放当前事务资源
            if (_currentTransaction != null)
            {
                _currentTransaction.Dispose();
                _currentTransaction = null;
            }
        }
    }
    #endregion
}
